#include "widget3d.h"
#include <QDebug>
#include "vmath.h"

#define BUFFER_OFFSET(offset) ((void*) (offset))

const GLfloat positions[] = {
    -1.0f, -1.0f, 0.0f, 1.0f,
    1.0f, -1.0f, 0.0f, 1.0f,
    -1.0f,  1.0f, 0.0f, 1.0f,
    -1.0f, -1.0f, 0.0f, 1.0f,
};

const GLfloat colors[] = {
    1.0f, 1.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 0.0f, 1.0f,
    1.0f, 0.0f, 1.0f, 1.0f,
    0.0f, 1.0f, 1.0f, 1.0f,
};

const vmath::mat4 models[] = {
    vmath::translate( -5.0f, 0.0f, 0.0f),
    vmath::translate( -2.0f, 0.0f, 0.0f),
    vmath::translate( 2.0f, 0.0f, 0.0f),
    vmath::translate( 0.0f, 0.0f, 0.0f),
};

const GLushort indices[] = {
    0, 1, 2, 3
};

Widget3D::Widget3D()
{
    setMinimumHeight(300);
//    QSurfaceFormat f = format();
//    f.setVersion(3, 30);
//    setFormat(f);
}

#define INSTANCE_COUNT 4

Widget3D::~Widget3D()
{

}

void Widget3D::initializeGL()
{
    qInfo()<<"initializeGL";
    initializeOpenGLFunctions();

    m_program = new QOpenGLShaderProgram(this);

    m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/triangles.vert");

    m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/triangles.frag");

    m_program->link();

    m_posAttr = m_program->attributeLocation("aPos");
    m_colorAttr = m_program->attributeLocation("aColor");
    m_matrixAttr = m_program->attributeLocation("modelMatrix");
    m_matrixAttr = 3;//get失败

    glGenVertexArrays(1, m_VAO);
    glGenBuffers(1, m_VBO);
    glGenBuffers(1, m_EBO);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glBindVertexArray(m_VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(positions)+sizeof(colors)+sizeof(vmath::mat4)*INSTANCE_COUNT, NULL, GL_STATIC_DRAW);

    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), positions);
    glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(colors), colors);
    glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions)+sizeof(colors), sizeof(models), models);

    glVertexAttribPointer(m_posAttr, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), BUFFER_OFFSET(0));
    glVertexAttribPointer(m_colorAttr, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), BUFFER_OFFSET(sizeof(positions)));

    glEnableVertexAttribArray(m_posAttr);
    glEnableVertexAttribArray(m_colorAttr);

    glVertexAttribDivisor(m_colorAttr, 1);//每个实例一个颜色，不是每个顶点一个颜色

//    glBindBuffer(GL_ARRAY_BUFFER, m_VBO[1]);
//    glBufferData(GL_ARRAY_BUFFER, sizeof(models), models, GL_STATIC_DRAW);

    for (int i = 0; i < 4; i++)
    {//遍历每一列设置2 3 4 5索引位
        glVertexAttribPointer(m_matrixAttr+i, 4, GL_FLOAT,
                              GL_FALSE,
                              sizeof(vmath::mat4),
                              BUFFER_OFFSET(sizeof(vmath::vec4)*i+sizeof(positions)+sizeof(colors)));

        glEnableVertexAttribArray(m_matrixAttr+i);
        glVertexAttribDivisor(m_matrixAttr+i, 1);
    }

    glBindBuffer(GL_ARRAY_BUFFER, 0);
//    resizeGL(428, 320);
}

void Widget3D::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void Widget3D::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 0.0f);
    glEnable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

    glClear(GL_COLOR_BUFFER_BIT);

    m_program->bind();

    glBindVertexArray(m_VAO[0]);

//    float aspect = 1.0;
//    vmath::mat4 view_matrix(vmath::translate(0.0f, 0.0f, -10.0f));
//    vmath::mat4 projection_matrix(vmath::frustum(-1.0f, 1.0f, -aspect, aspect, 1.0f, 500.0f));


//    int projection_matrix_loc = m_program->uniformLocation("projection_matrix");
//    int view_matrix_loc = m_program->uniformLocation("view_matrix");

//    glUniformMatrix4fv(projection_matrix_loc, 1, GL_FALSE, projection_matrix);
//    glUniformMatrix4fv(view_matrix_loc, 1, GL_FALSE, view_matrix);

    float aspect = 1.0;
    QMatrix4x4 projection_matrix;
    projection_matrix.frustum(-1.0f, 1.0f, -aspect, aspect, 1.0f, 500.0f);
    m_program->setUniformValue("projection_matrix", projection_matrix);

    QMatrix4x4 view_matrix;
    view_matrix.translate(0.0f, 0.0f, -10.0f);
    m_program->setUniformValue("view_matrix", view_matrix);

//    void * matrices = (void *)glMapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(positions) + sizeof(colors)+sizeof(models), GL_MAP_WRITE_BIT ); // opengl 3.x
//    void * matrices = (void *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); // opengl 2.0
//    if(matrices == NULL)
//    {
//        qInfo() << glGetError() << "!!!\n";
//        exit(-1);
//    }
//GL_INVALID_OPERATION
//    for (int n = 0; n < INSTANCE_COUNT; n++)
//    {

//        memcpy((char*)matrices+sizeof(QMatrix4x4)*n + sizeof(positions) + sizeof(colors),
//               (char*)models[n].data(),
//               sizeof(QMatrix4x4));
//    }

//    glUnmapBuffer(GL_ARRAY_BUFFER);

    glDrawArraysInstanced(GL_TRIANGLES, 0, 3, INSTANCE_COUNT);

    m_program->release();
}
